<?php
// +----------------------------------------------------------------------
// | YFCMF [ WE CAN DO IT MORE SIMPLE]
// +----------------------------------------------------------------------
// | Copyright (c) 2016-2020 http://yfcmf.net All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: rainfer <rainfer520@qq.com>
// +----------------------------------------------------------------------

// 应用公共文件
/**
 * 打印数组
 *
 * @param $arr
 *
 * @return mixed
 */
function p($arr)
{
    echo "<pre>" . print_r($arr, true) . "</pre>";
}

/**
 * 由当前时间戳 + 5位随机数生成文件名
 *
 * @return int 生成文件名
 */
function create_filename()
{
    return time() . mt_rand(10000, 99999);
}

/**
 * [check_mobile 校验 手机格式]
 *
 * @param  [type] $phone [description]
 *
 * @return [type]        [description]
 */
function check_mobile($phone)
{
    return preg_match("/1\d{10}$/", $phone);
}

/**
 * [check_email 校验邮箱格式]
 *
 * @param  [type] $email [description]
 *
 * @return [type]        [description]
 */
function check_email($email)
{
    $pattern = "/^([0-9A-Za-z\\-_\\.]+)@([0-9a-z]+\\.[a-z]{2,3}(\\.[a-z]{2})?)$/i";
    return preg_match($pattern, $email);
}

/**检测数字是否合法
 *
 * @param mixed $num
 * @param int $length 小数位数
 *
 * @return false|int
 */
function check_float($num, $length = 2)
{
    $rule = '/^[0-9]+(.[0-9]{1,' . $length . '})?$/';
    return preg_match($rule, $num);
}

/**
 * 用户密码加密方法，可以考虑盐值包含时间（例如注册时间），
 *
 * @param string $pass 原始密码
 * @param string $pass_salt 原始密码
 *
 * @return string 多重加密后的32位小写MD5码
 */
function encrypt_pass($pass, $pass_salt)
{
    return md5(sha1($pass) . $pass_salt);
}

/**
 * 16位md5，
 *
 * @param string $pass 原始密码
 *
 * @return string 多重加密后的16位小写MD5码
 */
function md5_short($pass)
{
    if ('' == $pass) {
        return '';
    }
    $salt = config('yfcmf.pass_salt');
    return substr(md5(sha1($pass) . $salt), 8, 16);
}

/**
 * CURL快捷方法，post提交数据
 *
 * @param string $url 提交目的地址
 * @param array $data post数据
 *
 * @return mixed
 */
function curl_post($url, $data, $header = [])
{
    $ch = curl_init();

    if (empty($header)) {
        $header = array("Accept-Charset: utf-8", 'Expect:');
    }
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
    curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
    curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
    curl_setopt($ch, CURLOPT_TIMEOUT, 60);
    // 最好加上http_build_query 转换，防止有些服务器不兼容
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $result = curl_exec($ch);
    curl_close($ch);
    return $result;
}

/**
 * CURL快捷方法，get提交数据
 *
 * @param string $url 提交目的地址
 * @param array $data post数据
 *
 * @return mixed
 */
function curl_get($url, $data, $header = [])
{
    $ch = curl_init();
    if (empty($header)) {
        $header = array("Accept-Charset: utf-8", 'Expect:');
    }
    $url = $url . '?' . http_build_query($data);
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
    curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
    curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
    curl_setopt($ch, CURLOPT_TIMEOUT, 60);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $result = curl_exec($ch);
    curl_close($ch);
    return $result;
}


/**
 * 生成随机验证码，每一位都是单独从字典中随机获取的字符，字典是0-9纯数字。
 *
 * @param number $length 验证码长度，默认6
 *
 * @return string 指定长度的随机验证码。
 */
function create_random($length = 6)
{
    $chars = "0123456789";
    $str = "";
    for ($i = 0; $i < $length; $i++) {
        $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
    }
    return $str;
}

if (!function_exists('random')) {
    /**
     * 随机字符
     *
     * @param int $length 长度
     * @param string $type 类型
     * @param int $convert 转换大小写 1大写 0小写
     *
     * @return string
     */
    function random($length = 10, $type = 'letter', $convert = 0)
    {
        $config = [
            'number' => '1234567890',
            'letter' => 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
            'string' => 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ23456789',
            'all' => 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
        ];
        if (!isset($config[$type])) {
            $type = 'letter';
        }
        $string = $config[$type];
        $code = '';
        $strlen = strlen($string) - 1;
        for ($i = 0; $i < $length; $i++) {
            $code .= $string{mt_rand(0, $strlen)};
        }
        if (!empty($convert)) {
            $code = ($convert > 0) ? strtoupper($code) : strtolower($code);
        }
        return $code;
    }
}

/**
 * 返回格式化信息
 *
 * @param string/array $msg 信息内容
 * @param string $code 错误码
 * @param number $status 状态 0 错误 ，1 成功
 *
 * @return array
 */
function msg_return($status = 0, $msg = null, $code = 0)
{
    return array('status' => $status, "code" => $code, "msg" => $msg);
}

/**
 * ajax 请求正确返回
 *
 * @param string $msg
 * @param array $data
 *
 * @return string
 */
function ajax_return_ok($data = array(), $msg = '')
{
    $result['status'] = 1;
    $result['data'] = $data;
    $result['msg'] = $msg;
    $result['code'] = 10000;
    // 返回JSON数据格式到客户端 包含状态信息
    header('Content-Type:application/json; charset=utf-8');
    exit(json_encode($result));
}

/**
 * ajax 请求错误返回
 *
 * @param string $msg
 * @param string $code
 *
 * @return string
 */
function ajax_return_error($msg = null, $code = 10001)
{
    if ($msg == null) {
        $msgDefault = config('error');
        $result['msg'] = $msgDefault [$code];
    } else {
        $result['msg'] = $msg;
    }
    $result['status'] = 0;
    $result['code'] = $code;
    // 返回JSON数据格式到客户端 包含状态信息
    header('Content-Type:application/json; charset=utf-8');
    exit(json_encode($result));
}

/**
 * 返回json
 *
 * @param array $data
 */
function json_return($data = array())
{
    // 返回JSON数据格式到客户端 包含状态信息
    header('Content-Type:application/json; charset=utf-8');
    exit(json_encode($data));
}

/**
 * 请求参数生成签名
 * @param $data
 *
 * @return string
 */
function data_auth_sign($data)
{
    //数据类型检测
    if (!is_array($data)) {
        $data = (array)$data;
    }
    ksort($data); //排序
    $code = http_build_query($data); //url编码并生成query字符串
    $sign = sha1($code); //生成签名
    return $sign;
}

/**
 * 输入特殊字符过滤
 *
 * @param $str
 *
 * @return string
 */
function str_filter($str)
{
    if (empty ($str) || "" == $str) {
        return "";
    }
    $str = strip_tags($str);
    $str = htmlspecialchars($str);
    $str = nl2br($str);
    $str = str_replace("select", "", $str);
    $str = str_replace("join", "", $str);
    $str = str_replace("union", "", $str);
    $str = str_replace("where", "", $str);
    $str = str_replace("insert", "", $str);
    $str = str_replace("delete", "", $str);
    $str = str_replace("update", "", $str);
    $str = str_replace("like", "", $str);
    $str = str_replace("drop", "", $str);
    $str = str_replace("create", "", $str);
    $str = str_replace("modify", "", $str);
    $str = str_replace("rename", "", $str);
    $str = str_replace("alter", "", $str);
    $str = str_replace("cast", "", $str);
    $str = str_replace('`', '', $str);
    $str = str_replace('·', '', $str);
    $str = str_replace('~', '', $str);
    $str = str_replace('!', '', $str);
    $str = str_replace('！', '', $str);
    $str = str_replace('@', '', $str);
    $str = str_replace('#', '', $str);
    $str = str_replace('$', '', $str);
    $str = str_replace('￥', '', $str);
    $str = str_replace('%', '', $str);
    $str = str_replace('^', '', $str);
    $str = str_replace('……', '', $str);
    $str = str_replace('&', '', $str);
    $str = str_replace('*', '', $str);
    $str = str_replace('(', '', $str);
    $str = str_replace(')', '', $str);
    $str = str_replace('（', '', $str);
    $str = str_replace('）', '', $str);
    $str = str_replace('-', '', $str);
    $str = str_replace('_', '', $str);
    $str = str_replace('——', '', $str);
    $str = str_replace('+', '', $str);
    $str = str_replace('=', '', $str);
    $str = str_replace('|', '', $str);
    $str = str_replace('\\', '', $str);
    $str = str_replace('[', '', $str);
    $str = str_replace(']', '', $str);
    $str = str_replace('【', '', $str);
    $str = str_replace('】', '', $str);
    $str = str_replace('{', '', $str);
    $str = str_replace('}', '', $str);
    $str = str_replace(';', '', $str);
    $str = str_replace('；', '', $str);
    $str = str_replace(':', '', $str);
    $str = str_replace('：', '', $str);
    $str = str_replace('\'', '', $str);
    $str = str_replace('"', '', $str);
    $str = str_replace('“', '', $str);
    $str = str_replace('”', '', $str);
    $str = str_replace(',', '', $str);
    $str = str_replace('，', '', $str);
    $str = str_replace('<', '', $str);
    $str = str_replace('>', '', $str);
    $str = str_replace('《', '', $str);
    $str = str_replace('》', '', $str);
    $str = str_replace('.', '', $str);
    $str = str_replace('。', '', $str);
    $str = str_replace('/', '', $str);
    $str = str_replace('、', '', $str);
    $str = str_replace('?', '', $str);
    $str = str_replace('？', '', $str);
    return trim($str);
}

/**
 * 系统加密方法
 *
 * @param string $data 要加密的字符串
 * @param string $key 加密密钥
 * @param int $expire 过期时间 单位 秒
 *
 * @return string
 */
function think_encrypt($data, $key = '', $expire = 0)
{
    $key = md5(empty($key) ? config('yfcmf.pass_salt') : $key);
    $data = base64_encode($data);
    $x = 0;
    $len = strlen($data);
    $l = strlen($key);
    $char = '';

    for ($i = 0; $i < $len; $i++) {
        if ($x == $l) $x = 0;
        $char .= substr($key, $x, 1);
        $x++;
    }

    $str = sprintf('%010d', $expire ? $expire + time() : 0);

    for ($i = 0; $i < $len; $i++) {
        $str .= chr(ord(substr($data, $i, 1)) + (ord(substr($char, $i, 1))) % 256);
    }

    $str = str_replace(array('+', '/', '='), array('-', '_', ''), base64_encode($str));
    return strtoupper(md5($str)) . $str;
}

/**
 * 系统解密方法
 *
 * @param  string $data 要解密的字符串 （必须是think_encrypt方法加密的字符串）
 * @param  string $key 加密密钥
 *
 * @return string
 */
function think_decrypt($data, $key = '')
{
    $key = md5(empty($key) ? config('yfcmf.pass_salt') : $key);
    $data = substr($data, 32);
    $data = str_replace(array('-', '_'), array('+', '/'), $data);
    $mod4 = strlen($data) % 4;
    if ($mod4) {
        $data .= substr('====', $mod4);
    }
    $data = base64_decode($data);
    $expire = substr($data, 0, 10);
    $data = substr($data, 10);

    if ($expire > 0 && $expire < time()) {
        return '';
    }
    $x = 0;
    $len = strlen($data);
    $l = strlen($key);
    $char = $str = '';

    for ($i = 0; $i < $len; $i++) {
        if ($x == $l) $x = 0;
        $char .= substr($key, $x, 1);
        $x++;
    }

    for ($i = 0; $i < $len; $i++) {
        if (ord(substr($data, $i, 1)) < ord(substr($char, $i, 1))) {
            $str .= chr((ord(substr($data, $i, 1)) + 256) - ord(substr($char, $i, 1)));
        } else {
            $str .= chr(ord(substr($data, $i, 1)) - ord(substr($char, $i, 1)));
        }
    }
    return base64_decode($str);
}

/**
 * 返回起止日期数组
 *
 * @param  string $start_date 开始日期 2019-09-01
 * @param  string $end_date 截止日期 2019-09-09
 * @param  string $format 格式
 *
 * @return array
 */
function date_rang($start_date, $end_date, $format = 'Y-m-d')
{
    $dates = range(strtotime($start_date), strtotime($end_date), 24 * 3600);
    foreach ($dates as &$date) {
        $date = date($format, $date);
    }
    return $dates;
}

/**
 * 生成时间区间条件
 *
 * @param $time_str
 * @param string $filed
 *
 * @return array
 */
function where_between_time($time_str, $filed = 'createTime', $format = '')
{
    date_default_timezone_set("Asia/Shanghai");
    $where = [];
    if (in_array($time_str, ['yesterday', 'today', 'week', 'month', 'quarter', 'year'])) {
        switch ($time_str) {
            case 'yesterday':
                $start = mktime(0, 0, 0, date('m'), date('d') - 1, date('Y'));
                $end = mktime(23, 59, 59, date('m'), date('d') - 1, date('Y'));
                break;
            case 'today':
                $start = mktime(0, 0, 0, date('m'), date('d'), date('Y'));
                $end = mktime(23, 59, 59, date('m'), date('d'), date('Y'));
                break;
            case 'week':
                $timestamp = time();
                $start = strtotime(date('Y-m-d', strtotime("this week Monday", $timestamp)));
                $end = strtotime(date('Y-m-d', strtotime("this week Sunday", $timestamp))) + 24 * 3600 - 1;
                break;
            case 'month':
                $start = mktime(0, 0, 0, date('m'), 1, date('Y'));
                $end = mktime(23, 59, 59, date('m'), date('t'), date('Y'));
                break;
            case 'quarter':
                $season = ceil((date('n')) / 3);
                $start = mktime(0, 0, 0, $season * 3 - 3 + 1, 1, date('Y'));
                $end = mktime(23, 59, 59, $season * 3, date('t', mktime(0, 0, 0, $season * 3, 1, date("Y"))), date('Y'));
                break;
            case 'year':
                $start = mktime(0, 0, 0, 1, 1, date('Y'));
                $end = mktime(23, 59, 59, 12, 31, date('Y'));
                break;
        }
        if ($format) {
            $start = date($format, $start);
            $end = date($format, $end);
        }
        $where[] = [$filed, 'between', [$start, $end]];
    }
    return $where;
}

/**
 * 是否为蜘蛛
 *
 * @param $ua
 */
function ua_is_spider($ua = null)
{
    if (!$ua) {
        return false;
    }
    $bots = array(
        'google' => 'google',
        'bingbot' => 'bing',
        'msnbot' => 'bing',
        'yahoo' => 'yahoo',
        'yahoo!' => 'yahoo',
        'Y!J-ASR' => 'yahoo',
        'ia_archiver' => 'alexa',
        'yandex' => 'yandex',
        'baiduspider' => 'baidu',
        'Baidu-YunGuanCe' => 'baiduyun',
        '360spider' => 'so',
        'haosou' => 'so',
        'Sogou web spider' => 'sogou',
        'soso.com' => 'soso',
        'Yisouspider' => 'yisou',
        'OrangeBot' => 'orange',
    );
    foreach ($bots as $bot_str => $bot_name) {
        if (false !== stripos($ua, $bot_str)) {
            return $bot_name;
        }
    }
    return false;
}

/**
 * 是否为其它机器人
 *
 * @param $ua
 *
 * @return bool
 */
function ua_is_bot($ua = null)
{
    if (!$ua) {
        return true;
    }
    // main spider
    if (ua_is_spider($ua)) {
        return true;
    }
    // has no os
    if (!ua_has_os($ua)) {
        return true;
    }
    // bot string
    $bots = array('google', 'bing', 'yandex', 'msnbot', 'altavista', 'googlebot', 'slurp', 'blackwidow', 'bot', 'chinaclaw', 'custo', 'disco', 'download', 'demon', 'ecatch', 'eirgrabber', 'emailsiphon', 'emailwolf', 'superhttp', 'surfbot', 'webwhacker', 'express', 'webpictures', 'extractorpro', 'eyenetie', 'flashget', 'getright', 'getweb!', 'go!zilla', 'go-ahead-got-it', 'grabnet', 'grafula', 'hmview', 'rafula', 'httrack', 'stripper', 'sucker', 'indy', 'interget', 'ninja', 'jetcar', 'spider', 'larbin', 'leechftp', 'downloader', 'tool', 'navroad', 'nearsite', 'netants', 'takeout', 'wwwoffle', 'netspider', 'vampire', 'netzip', 'octopus', 'offline', 'pagegrabber', 'foto', 'pavuk', 'pcbrowser', 'realdownload', 'reget', 'sitesnagger', 'smartdownload', 'superbot', 'webspider', 'teleport', 'voideye', 'collector', 'webauto', 'webcopier', 'webfetch', 'webgo', 'webleacher', 'webreaper', 'websauger', 'extractor', 'quester', 'webstripper', 'webzip', 'wget', 'widow', 'zeus', 'twengabot', 'htmlparser', 'libwww', 'python', 'perl', 'urllib', 'scan', 'curl', 'email', 'pycurl', 'pyth', 'pyq', 'webcollector', 'webcopy', 'webcraw', 'ezooms', 'bingbot', 'grapeshotcrawler', 'mj12bot', 'yandexbot', 'proximic', 'magpie-crawler', 'daumoa', 'changedetection', 'ia_archiver', 'genieo web filter', 'naverbot', 'metajobbot', 'baiduspider', 'seznambot', 'exabot', 'sogou web spider', 'woko', '360spider', 'coccoc', 'turnitinbot', 'archive.org_bot', 'shopwiki', 'exb language crawler', 'vagabondo', 'zumbot', 'spinn3r', 'mail.ru bot', 'bixocrawler', 'addthis.com', 'netestate crawler', 'netseer', 'careerbot', 'sistrix', 'linkdexbot', 'nuhk', 'qualidator.com bot', 'bitlybot', 'spbot', 'aihitbot', 'bingpreview', 'a6-indexer', '80legs', 'umbot', 'ahrefsbot', 'cliqzbot', 'seocheckbot', 'psbot', 'voilabot', 'searchmetricsbot', 'rogerbot', 'showyoubot', 'yahoo', 'butterfly', 'urlappendbot', 'plukkie', 'yacybot', 'thumbshots-de-bot', 'jyxobot', 'aboundexbot', 'unisterbot', 'bubing', 'trendictionbot', 'cms crawler', 'immediatenet thumbnails', 'uaslinkchecker', 'blekkobot', 'netcraftsurveyagent', 'wotbox', 'compspybot', 'yioopbot', 'qualidator.com siteanalyzer 1.0', 'najdi.si', 'meanpathbot', 'tineye', 'qirina hurdler', 'begunadvertising', 'luminatebot', 'fyberspider', 'infohelfer', 'linkdex.com', 'curious george', 'adressendeutschland.de', 'fetch-guess', 'ichiro', 'mojeekbot', 'sbsearch', 'webthumbnail', 'socialbm_bot', 'semrushbot', 'vedma', 'alexa site audit', 'seokicks-robot', 'browsershots', 'hubspot connect', 'blexbot', 'woriobot', 'search.kumkie.com', 'seoengbot', 'arabot', 'amznkassocbot', 'speedy', 'parsijoo', 'obot', 'hosttracker', 'openwebspider', 'wbsearchbot', 'facebookexternalhit', 'krowler', 'icjobs', 'istellabot', 'findlinks', 'integromedb', 'flipboardproxy', 'nigma.ru', 'backlinkcrawler', 'peeplo screenshot bot', 'panscient web crawler', 'ccresearchbot', 'semantifire', 'linkaider', 'zookabot', 'crawler4j', 'screenerbot crawler', 'cloudservermarketspider', 'webmastercoffee', 'paperlibot', 'queryseekerspider', 'crowsnest', 'unwindfetchor', 'metauri api', 'miadev', 'acoonbot', 'steeler', 'gigabot', 'firmilybot', 'sosospider', 'openindexspider', 'metaheadersbot', 'strokebot', 'geliyoobot', 'ccbot', 'bot-pge.chlooe.com', 'owncloud server crawler', 'cirrusexplorer', 'procogseobot', 'falconsbot', 'dlvr.it/1.0', '200pleasebot', 'discoverybot', 'r6 bot', 'bl.uk_lddc_bot', 'solomonobot', 'grahambot', 'automattic analytics crawler', 'emefgebot', 'youdaobot', 'piplbot', 'flightdeckreportsbot', 'fastbot crawler', '4seohuntbot', 'updownerbot', 'jikespider', 'nlnz_iaharvester2013', 'wsanalyzer', 'yodaobot', 'spiderling', 'esribot', 'thumbshots.ru', 'blogpulse', 'nextgensearchbot', 'bot.wsowner.com', 'wscheck.com', 'qseero', 'drupact', 'huaweisymantecspider', 'pagepeeker', 'hometags', 'facebookplatform', 'pixray-seeker', 'bdfetch', 'memonewsbot', 'procogbot', 'willybot', 'peerindex', 'job roboter spider', 'mlbot', 'webnl', 'peepowbot', 'semager', 'mia bot', 'heritrix', 'eurobot', 'dripfeedbot', 'webinatorbot', 'whoismindbot', 'bad-neighborhood', 'hailoobot', 'akula', 'metamojicrawler', 'page2rss', 'easybib autocite', 'suggybot', 'nerdbynature.bot', 'eventgurubot', 'quickobot', 'gonzo', 'bnf.fr_bot', 'uptimerobot', 'influencebot', 'msrbot', 'keyworddensityrobot', 'ronzoobot', 'ryzecrawler', 'scoutjet', 'twikle', 'swebot', 'radar-bot', 'dcpbot', 'castabot', 'percbotspider', 'wesee:search', 'catchbot', 'imbot', 'edisterbot', 'wasalive-bot', 'accelobot', 'postpost', 'factbot', 'setoozbot', 'biwec', 'garlikcrawler', 'search17bot', 'lijit', 'metageneratorcrawler', 'robots_tester', 'just-crawler', 'apercite', 'pmoz.info odp link checker', 'lemurwebcrawler', 'covario-ids', 'holmes', 'rankurbot', 'dotbot', 'adsbot-google', 'envolk', 'ask jeeves/teoma', 'lexxebot', 'stackrambler', 'abrave spider', 'evrinid', 'arachnode.net', 'camontspider', 'wikiwix-bot', 'nymesis', 'sitedomain-bot', 'seodat', 'sygolbot', 'snapbot', 'opencalaissemanticproxy', 'cligoorobot', 'cityreview', 'nworm', 'aboutusbot', 'icc-crawler', 'sbider', 'dot tk - spider', 'euripbot', 'parchbot', 'peew', 'antbot', 'yrspider', 'urlfilebot (urlbot)', 'gaisbot', 'watchmouse', 'tagoobot', 'motoricerca-robots.txt-checker', 'webwatch/robot_txtchecker', 'urlfan-bot', 'statoolsbot', 'page_verifier', 'sslbot', 'sai crawler', 'domaindb', 'linkwalker', 'wmcai_robot', 'voyager', 'copyright sheriff', 'ocelli', 'twiceler', 'amibot', 'abby', 'netresearchserver', 'videosurf_bot', 'xml sitemaps generator', 'blinkacrawler', 'nodestackbot', 'pompos', 'taptubot', 'babaloospider', 'yaanb', 'girafabot', 'livedoor screenshot', 'ecairn-grabber', 'faubot', 'toread-crawler', 'metauri', 'l.webis', 'web-sniffer', 'fairshare', 'ruky-roboter', 'thumbshots-bot', 'botonparade', 'amagit.com', 'hatenascreenshot', 'holmesbot', 'dotsemantic', 'karneval-bot', 'hosttracker.com', 'aportworm', 'xmarksfetch', 'feedfinder/bloggz.se', 'corpuscrawler', 'willow internet crawler', 'orgbybot', 'gingercrawler', 'pingdom.com_bot', 'nutch', 'baypup', 'linguee bot', 'mp3bot', '192.comagent', 'surphace scout', 'wikiofeedbot', 'szukacz', 'dblbot', 'thumbnail.cz robot', 'linguabot', 'gurujibot', 'charlotte', '50.nu', 'sanszbot', 'moba-crawler', 'heartrails_capture', 'surveybot', 'mnogosearch', 'smart.apnoti.com robot', 'topicbot', 'jadynavebot', 'osobot', 'webimages', 'winwebbot', 'scooter', 'scarlett', 'goforitbot', 'dkimrepbot', 'yanga', 'dns-digger-explorer', 'robozilla', 'yowedobot', 'botmobi', 'fooooo_web_video_crawl', 'uptimedog', 'nail', 'metaspinner/0.01', 'touche', 'rssmicro.com rss/atom feed robot', 'sniffrss', 'kalooga', 'feedcatbot', 'webrankspider', 'flatland industries web spider', 'dealgates bot', 'link valet online', 'shelob', 'technoratibot', 'flocke bot', 'followsite bot', 'visbot');
    foreach ($bots as $bot) {
        if (false !== stripos($ua, $bot)) {
            return true;
        }
    }
    return false;
}

/**
 * 是否有操作系统
 *
 * @param $ua
 *
 * @return mixed
 */
function ua_has_os($ua = null)
{
    if (!$ua) {
        return false;
    }
    $os_arr = array(
        'Android' => 'AND',
        'Maemo' => 'MAE',
        'CrOS ' => 'LIN',
        'Linux' => 'LIN',
        'Xbox' => 'XBX',
        // workaround for vendors who changed the WinPhone 7 user agent
        'WP7' => 'WPH',
        'CYGWIN_NT-6.2' => 'WI8',
        'Windows NT 6.2' => 'WI8',
        'Windows NT 6.3' => 'WI8',
        'Windows 8' => 'WI8',
        'CYGWIN_NT-6.1' => 'WI7',
        'Windows NT 6.1' => 'WI7',
        'Windows 7' => 'WI7',
        'CYGWIN_NT-6.0' => 'WVI',
        'Windows NT 6.0' => 'WVI',
        'Windows Vista' => 'WVI',
        'CYGWIN_NT-5.2' => 'WS3',
        'Windows NT 5.2' => 'WS3',
        'Windows Server 2003 / XP x64' => 'WS3',
        'CYGWIN_NT-5.1' => 'WXP',
        'Windows NT 5.1' => 'WXP',
        'Windows XP' => 'WXP',
        'CYGWIN_NT-5.0' => 'W2K',
        'Windows NT 5.0' => 'W2K',
        'Windows 2000' => 'W2K',
        'CYGWIN_NT-4.0' => 'WNT',
        'Windows NT 4.0' => 'WNT',
        'WinNT' => 'WNT',
        'Windows NT' => 'WNT',
        'CYGWIN_ME-4.90' => 'WME',
        'Win 9x 4.90' => 'WME',
        'Windows ME' => 'WME',
        'CYGWIN_98-4.10' => 'W98',
        'Win98' => 'W98',
        'Windows 98' => 'W98',
        'CYGWIN_95-4.0' => 'W95',
        'Win32' => 'W95',
        'Win95' => 'W95',
        'Windows 95' => 'W95',
        // Windows Phone OS 7 and above
        'Windows Phone OS' => 'WPH',
        // Windows Mobile 6.x and some later versions of Windows Mobile 5
        'IEMobile' => 'WMO', // fallback
        'Windows Mobile' => 'WMO',
        // Windows CE, Pocket PC, and Windows Mobile 5 are indistinguishable without vendor/device specific detection
        'Windows CE' => 'WCE',
        'iPod' => 'IPD',
        'iPad' => 'IPA',
        'iPhone' => 'IPH',
        // 'iOS'                       => 'IOS',
        'Darwin' => 'MAC',
        'Macintosh' => 'MAC',
        'Power Macintosh' => 'MAC',
        'Mac_PowerPC' => 'MAC',
        'Mac PPC' => 'MAC',
        'PPC' => 'MAC',
        'Mac PowerPC' => 'MAC',
        'Mac OS' => 'MAC',
        'webOS' => 'WOS',
        'Palm webOS' => 'WOS',
        'PalmOS' => 'POS',
        'Palm OS' => 'POS',
        'BB10' => 'BBX',
        'BlackBerry' => 'BLB',
        'RIM Tablet OS' => 'QNX',
        'QNX' => 'QNX',
        'SymbOS' => 'SYM',
        'Symbian OS' => 'SYM',
        'SymbianOS' => 'SYM',
        'bada' => 'SBA',
        'SunOS' => 'SOS',
        'AIX' => 'AIX',
        'HP-UX' => 'HPX',
        'OpenVMS' => 'VMS',
        'FreeBSD' => 'BSD',
        'NetBSD' => 'NBS',
        'OpenBSD' => 'OBS',
        'DragonFly' => 'DFB',
        'Syllable' => 'SYL',
        'Nintendo WiiU' => 'WIU',
        'Nintendo Wii' => 'WII',
        'Nitro' => 'NDS',
        'Nintendo DSi' => 'DSI',
        'Nintendo DS' => 'NDS',
        'Nintendo 3DS' => '3DS',
        'PlayStation Vita' => 'PSV',
        'PlayStation Portable' => 'PSP',
        'PlayStation 3' => 'PS3',
        'IRIX' => 'IRI',
        'OSF1' => 'T64',
        'OS/2' => 'OS2',
        'BEOS' => 'BEO',
        'Amiga' => 'AMI',
        'AmigaOS' => 'AMI',
    );
    foreach ($os_arr as $k => $v) {
        if (false !== stripos($ua, $k)) {
            return $v;
        }
    }
    return false;
}

function ua_has_browser($ua = null)
{
    if (!$ua) {
        return false;
    }
    $bs = array(
        'abrowse' => 'AB',
        'amaya' => 'AM',
        'amigavoyager' => 'AV',
        'amiga-aweb' => 'AW',
        'arora' => 'AR',
        'beonex' => 'BE',

        // BlackBerry smartphones and tablets
        'blackberry' => 'BB', // BlackBerry 6 and PlayBook adopted webkit
        'bb10' => 'B2', // BlackBerry 10
        'playbook' => 'BP',

        'browsex' => 'BX',

        // Camino (and earlier incarnation)
        'chimera' => 'CA',
        'camino' => 'CA',

        'cheshire' => 'CS',

        // Chrome, Chromium, and ChromePlus
        'crmo' => 'CH',
        'chrome' => 'CH',

        // Chrome Frame
        'chromeframe' => 'CF',

        'cometbird' => 'CO',
        'dillo' => 'DI',
        'elinks' => 'EL',
        'epiphany' => 'EP',
        'fennec' => 'FE',

        // Dolfin (or Dolphin)
        'dolfin' => 'DF',

        // Firefox (in its many incarnations and rebranded versions)
        'phoenix' => 'PX',
        'mozilla firebird' => 'FB',
        'firebird' => 'FB',
        'bonecho' => 'FF',
        'minefield' => 'FF',
        'namoroka' => 'FF',
        'shiretoko' => 'FF',
        'granparadiso' => 'FF',
        'iceweasel' => 'FF',
        'icecat' => 'FF',
        'firefox' => 'FF',

        'thunderbird' => 'TB',

        'flock' => 'FL',
        'fluid' => 'FD',
        'galeon' => 'GA',
        'google earth' => 'GE',
        'hana' => 'HA',
        'hotjava' => 'HJ',
        'ibrowse' => 'IB',
        'icab' => 'IC',

        // IE (including shells: Acoo, AOL, Avant, Crazy Browser, Green Browser, KKMAN, Maxathon)
        'msie' => 'IE',
        'trident' => 'IE',
        'microsoft internet explorer' => 'IE',
        'internet explorer' => 'IE',

        'iron' => 'IR',
        'kapiko' => 'KP',
        'kazehakase' => 'KZ',
        'k-meleon' => 'KM',
        'konqueror' => 'KO',
        'links' => 'LI',
        'lynx' => 'LX',
        'midori' => 'MI',

        // SeaMonkey (formerly Mozilla Suite) (and rebranded versions)
        'mozilla' => 'MO',
        'gnuzilla' => 'SM',
        'iceape' => 'SM',
        'seamonkey' => 'SM',

        // NCSA Mosaic (and incarnations)
        'mosaic' => 'MC',
        'ncsa mosaic' => 'MC',

        // Netscape Navigator
        'navigator' => 'NS',
        'netscape6' => 'NS',
        'netscape' => 'NS',

        'nx' => 'NF',
        'netfront' => 'NF',

        'omniweb' => 'OW',

        // Opera
        'nitro) opera' => 'OP',
        'opera' => 'OP',

        'rekonq' => 'RK',

        // Safari
        'safari' => 'SF',
        'applewebkit' => 'SF',

        'titanium' => 'TI',

        'webos' => 'WO',
        'webpro' => 'WP',
    );

    $browsers = $bs;

    // derivative browsers often clone the base browser's useragent
    unset($browsers['firefox']);
    unset($browsers['mozilla']);
    unset($browsers['safari']);
    unset($browsers['applewebkit']);

    $browsersPattern = str_replace(')', '\)', implode('|', array_keys($browsers)));
    $results = array();

    // Misbehaving IE add-ons
    $ua = preg_replace('/[; ]Mozilla\/[0-9.]+ \([^)]+\)/', '', $ua);
    // Clean-up BlackBerry device UAs
    $ua = preg_replace('~^BlackBerry\d+/~', 'BlackBerry/', $ua);

    if (preg_match_all("/($browsersPattern)[\/\sa-z(]*([0-9]+)([\.0-9a-z]+)?/i", $ua, $results)
        || (strpos($ua, 'Shiira') === false && preg_match_all("/(firefox|thunderbird|safari)[\/\sa-z(]*([0-9]+)([\.0-9a-z]+)?/i", $ua, $results))
        || preg_match_all("/(applewebkit)[\/\sa-z(]*([0-9]+)([\.0-9a-z]+)?/i", $ua, $results)
        || preg_match_all("/^(mozilla)\/([0-9]+)([\.0-9a-z-]+)?(?: \[[a-z]{2}\])? (?:\([^)]*\))$/i", $ua, $results)
        || preg_match_all("/^(mozilla)\/[0-9]+(?:[\.0-9a-z-]+)?\s\(.* rv:([0-9]+)([.0-9a-z]+)\) gecko(\/[0-9]{8}|$)(?:.*)/i", $ua, $results)
        || (strpos($ua, 'Nintendo 3DS') !== false && preg_match_all("/^(mozilla).*version\/([0-9]+)([.0-9a-z]+)?/i", $ua, $results))
    ) {
        // browser code (usually the first match)
        $count = 0;
        $id = $browsers[strtolower($results[1][0])];
        // sometimes there's a better match at the end
        if (strpos($ua, 'chromeframe') !== false) {
            $count = count($results[0]) - 1;
            $id = 'CF';
        } elseif (($id == 'IE' || $id == 'LX') && (count($results[0]) > 1)) {
            $count = count($results[0]) - 1;
            $id = $browsers[strtolower($results[1][$count])];
        }
        // Netscape fix
        if ($id == 'MO' && $count == 0) {
            if (stripos($ua, 'PlayStation') !== false) {
                return false;
            }
            if (strpos($ua, 'Nintendo 3DS') !== false) {
                $id = 'NF';
            } elseif (count($results) == 4) {
                $id = 'NS';
            }
        } // BlackBerry devices
        elseif (strpos($ua, 'BlackBerry') !== false) {
            $id = 'BB';
        } elseif (strpos($ua, 'RIM Tablet OS') !== false) {
            $id = 'BP';
        } elseif (strpos($ua, 'BB10') !== false) {
            $id = 'B2';
        } elseif (strpos($ua, 'Playstation Vita') !== false) {
            $id = 'NF';
        }
        return $id;
    }
    return false;
}

/**
 * 来源
 *
 * @param $referer
 *
 * @return mixed
 */
function has_referer($referer)
{
    if (!$referer) {
        return false;
    }
    if (!filter_var($referer, FILTER_VALIDATE_URL)) {
        return false;
    }
    $from = @parse_url($referer, PHP_URL_HOST);
    return $from ? preg_replace('~^www\.~', '', strtolower($from)) : false;
}
